﻿using Microsoft.Extensions.Options;
using Shop.Core.Config;
using Shop.Core.Repository;
using Shop.Core.Share;
using Shop.Core.YOP;
using Shop.IServices;
using Shop.IServices.Admin;
using Shop.Model.Dto.Admin.DrawMoney;
using Shop.Model.Entity.Jur;
using Shop.Model.Entity.System;
using Shop.Model.Entity.Use;
using Shop.Model.View.Admin.DrawMoney;
using SqlSugar;

namespace Shop.Services.Admin;

public class DrawMoneyService: AbstractService, IDrawMoneyService
{
    private readonly RepositoryBase<UseDrawMoneyEntity> _drawMoneyRepository;
    private readonly RepositoryBase<UserWalletLog> _walletLogRepository;
    private readonly RepositoryBase<UserWallet> _walletRepository;
    private readonly RepositoryBase<UseCardEntity> _cardRepository;
    private readonly RepositoryBase<SysConstantEntity> _constantRepository;
    private readonly IWechatAppService _wechatAppService;
    private readonly CallBackUrlConfig _callBackUrlConfig;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="drawMoneyRepository"></param>
    /// <param name="walletLogRepository"></param>
    /// <param name="walletRepository"></param>
    /// <param name="cardRepository"></param>
    /// <param name="wechatAppService"></param>
    /// <param name="callBackUrlConfig"></param>
    public DrawMoneyService(RepositoryBase<UseDrawMoneyEntity> drawMoneyRepository,
        RepositoryBase<UserWalletLog> walletLogRepository,
        RepositoryBase<UserWallet> walletRepository,
        RepositoryBase<UseCardEntity> cardRepository,
        IWechatAppService wechatAppService,
        IOptions<CallBackUrlConfig> callBackUrlConfig,
        RepositoryBase<SysConstantEntity> constantRepository)
    {
        _drawMoneyRepository = drawMoneyRepository;
        _walletLogRepository = walletLogRepository;
        _walletRepository = walletRepository;
        _cardRepository = cardRepository;
        _wechatAppService = wechatAppService;
        _callBackUrlConfig = callBackUrlConfig.Value;
        _constantRepository = constantRepository;
    }

    /// <summary>
    /// 提现列表
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AppResult<PageModel<DrawMoneyListVo>> DrawMoneyList(DrawMoneyListDto dto)
    {
        var records = 0;
        var data = _drawMoneyRepository.Queryable<UseDrawMoneyEntity, UserWalletLog, UseUser, JurUser>(
                (t1, t2, t3, t4) =>
                    new object[]
                    {
                        JoinType.Left, t1.WalletLog == t2.Id,
                        JoinType.Left, t1.User == t3.Id,
                        JoinType.Left, t1.Operator == t4.Id
                    })
            .WhereIF(dto.Code.HasValue, (t1, t2, t3, t4) => t3.Code == dto.Code.Value)
            .WhereIF(!string.IsNullOrEmpty(dto.Tele), (t1, t2, t3, t4) => t3.Tele == dto.Tele)
            .WhereIF(dto.State.HasValue, (t1, t2, t3, t4) => t1.State == dto.State.Value)
            .WhereIF(dto.StartTime.HasValue, (t1, t2, t3, t4) => t1.FoundTime >= dto.StartTime.Value)
            .WhereIF(dto.EndTime.HasValue, (t1, t2, t3, t4) => t1.FoundTime < dto.EndTime.Value)
            .WhereIF(dto.Type.HasValue, (t1, t2, t3, t4) => t1.Type == dto.Type.Value)
            .Where((t1, t2, t3) => t1.FoundTime < DateTime.Now.Date)
            .OrderBy("t1.FoundTime DESC")
            .Select((t1, t2, t3, t4) => new DrawMoneyListVo()
            {
                Id = t1.Id,
                Code = t3.Code,
                Name = t3.Nickname,
                FoundTime = t1.FoundTime,
                Type = t1.Type,
                Amount = t2.Amount,
                State = t1.State,
                DisposeTime = t1.DisposeTime,
                Operator = t4.Name,
                OperatorTime = t1.OperatorTime
            })
            .ToPageList(dto.PageIndex, dto.PageSize, ref records);
        return new PageModel<DrawMoneyListVo>(dto, data, records);
    }

    /// <summary>
    /// 提现审核
    /// </summary>
    /// <param name="dto"></param>
    /// <param name="uId"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public async Task<AppResult> DrawMoneyCheck(DrawMoneyCheckDto dto, long uId)
    {
        var adminInfo = _constantRepository.Where(x => x.Key == "drawings_admin_id").Select(x => x.Value).First();
        if (uId != long.Parse(adminInfo))
            return Problem("您无此操作权限");
        var drawMoneyInfo = _drawMoneyRepository.Where(x => x.Id == dto.Id).First();
        if (drawMoneyInfo == null)
            return Problem("提现记录错误");
        if (drawMoneyInfo.State != 0)
            return Problem("此提现记录状态不允许操作！");
        var walletLogInfo = _walletLogRepository.Where(x => x.Id == drawMoneyInfo.WalletLog).First();
        var walletInfo = _walletRepository.GetFirst(x => x.UserId == walletLogInfo.UserId);
        if (!dto.IsState)
        {
            drawMoneyInfo.State = -1;
            drawMoneyInfo.DisposeTime = DateTime.Now;
            drawMoneyInfo.Operator = uId;
            drawMoneyInfo.OperatorTime = DateTime.Now;
            walletLogInfo.State = -1;
            walletLogInfo.FinishTime = DateTime.Now;
            walletInfo.Balance += walletLogInfo.Amount;
            _walletRepository.Update(walletInfo);
            _drawMoneyRepository.Update(drawMoneyInfo);
            _walletLogRepository.Update(walletLogInfo);
            return new AppResult();
        }

        if (drawMoneyInfo.Type == 1)
        {
            var user = _walletRepository.Queryable<UseUser>().First(x => x.Id == drawMoneyInfo.User);
            var result = await _wechatAppService.TransferBatches(drawMoneyInfo.Id.ToString(), user.AppletOpenId, user.Nickname, walletLogInfo.Amount - walletLogInfo.Procedure);
            if (!result.IsError)
            {
                drawMoneyInfo.State = 2;
                drawMoneyInfo.Operator = uId;
                drawMoneyInfo.OperatorTime = DateTime.Now;
                walletLogInfo.State = 1;
                walletLogInfo.FinishTime = DateTime.Now;
                walletInfo.Withdrawable += walletLogInfo.Amount;
                _walletRepository.Update(walletInfo);
                _drawMoneyRepository.Update(drawMoneyInfo);
                _walletLogRepository.Update(walletLogInfo);
                return Success();
            }
            else
            {
                return result.Message switch
                {
                    "NOT_ENOUGH" => Problem("商户账户资金不足"),
                    "ACCOUNTERROR" => Problem("商户账户付款受限"),
                    "QUOTA_EXCEED" => Problem("超出商户单日转账额度"),
                    "FREQUENCY_LIMITED" => Problem("频率超限,清等一会再试"),
                    "NO_AUTH" => Problem("商户信息不合法"),
                    "INVALID_REQUEST" => Problem("参数不符合业务规则"),
                    "PARAM_ERROR" => Problem("请求参数错误"),
                    "APPID_MCHID_NOT_MATCH" => Problem("商户号和appid没有绑定关系"),
                    "SYSTEM_ERROR" => Problem("系统错误"),
                    _ => Problem($"转账失败。错误:{result.Message}"),
                };
            }
        }
        else if (drawMoneyInfo.Type == 2)
        {
            var cardInfo = _cardRepository.Where(x => x.Id == drawMoneyInfo.Card).First();
            var result = YopPay.Transfer(drawMoneyInfo.Id.ToString(), walletLogInfo.Amount - walletLogInfo.Procedure, cardInfo.Card,
                cardInfo.Possessor, cardInfo.Coding, _callBackUrlConfig.YOPTransfer);
            if (result.returnCode == "UA00000")
            {
                drawMoneyInfo.State = 1;
                drawMoneyInfo.Operator = uId;
                drawMoneyInfo.OperatorTime = DateTime.Now;
                _drawMoneyRepository.Update(drawMoneyInfo);
                return Success();
            }
            else
            {
                return result.returnCode switch
                {
                    "UA30012" or "UA30044" => Problem("账户余额不足"),
                    "UA30013" => Problem("订单已存在，请勿重复发起"),
                    "UA40001" => Problem("金额不正确"),
                    "UA5010" => Problem("开户银行编码或开户支行编码不正确"),
                    _ => Problem($"打款失败。错误:{result.returnCode}"),
                };
            }              
        }
        else
            return Problem("提现类型错误");
    }
}